package com.ddy.test.socket;

import com.ddy.test.ByteTest;
import com.ddy.test.awt.MouseTest;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by ddy on 2020/6/8 1:42 PM
 */

public class SocketClient{

    private static final String SERVER_IP = "192.168.1.201";
//    private static final String SERVER_IP = "localhost";
    private static final int SERVER_PORT = 5111;

    private static final String TYPE_KEY = "Key";
    private static final String TYPE_FILE = "File";
    private static final String TYPE_CURSOR = "Cursor";

    private DataOutputStream dataOutputStream = null;
    private Socket client;
    private InputStream inputStream;
    private static SocketClient socketClient;
    private static final long MAX_TOTAL_LENGTH = 1024 * 1024 * 1024;


    private static int timerCount = 0;

    private static final int[] mouseStatus = {0};


    private SocketClient(){
        try {
            client = new Socket(SERVER_IP, SERVER_PORT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void close() throws IOException {
        client.close();
    }

    private void sendStream(String filePath) throws InterruptedException, IOException {
        sendFile(filePath, MAX_TOTAL_LENGTH);
        sendEndFlag();
    }

    private void sendEndFlag() throws InterruptedException, IOException {
        dataOutputStream = getDataOutputStream();
        Thread.sleep(1000);
        dataOutputStream.write(new byte[]{0,0,0});
        System.out.println("send end flag~~");
    }


    private void sendFile(String filePath, long totalLength) throws InterruptedException {
        File file = new File(filePath);
        long remianing=totalLength, sendedLength=0;
        if(totalLength < 0){
            totalLength = file.length();
            remianing = totalLength;
        }
        int count=0;
        System.out.println("file length: " + totalLength);
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            dataOutputStream = getDataOutputStream();
            String fileName = file.getName();
            String header = TYPE_FILE + "=" + totalLength ;
            byte[] headerBytes = ByteTest.generateHeaderBytes(header);
            System.out.println(new String(headerBytes) + ", " + totalLength);
            dataOutputStream.write(headerBytes);
            byte[] fileNameBytes = ByteTest.generateFileNameBytes(fileName);
            System.out.println(new String(fileNameBytes));
            dataOutputStream.write(fileNameBytes);

            byte[] array = new byte[4096];
            int readLength;
            while ((readLength = fileInputStream.read(array, 0, array.length)) != -1){
                count++;
                remianing -= readLength;
                sendedLength +=readLength;
//                System.out.println("reading " + count + ", length=" + readLength + ", sendedLength: " + sendedLength + ", remaining: " + remianing);
                dataOutputStream.write(array, 0, readLength);
//                dataOutputStream.flush();
            }
            System.out.println("reading " + count + ", length=" + readLength + ", sendedLength: " + sendedLength + ", remaining: " + remianing);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void sendCursorHeader() throws IOException {
        dataOutputStream = getDataOutputStream();
        String header = TYPE_CURSOR + "=0";
        byte[] headerBytes = ByteTest.generateHeaderBytes(header);
        System.out.println(new String(headerBytes));
        dataOutputStream.write(headerBytes);
    }

    private void sendCursor(String cursor) throws IOException {
        dataOutputStream = getDataOutputStream();
        dataOutputStream.write(cursor.getBytes());
    }

    private void sendKey(String key) throws IOException {
        dataOutputStream = getDataOutputStream();
        String header = TYPE_KEY + "=" + key.getBytes().length ;
        byte[] headerBytes = ByteTest.generateHeaderBytes(header);
        System.out.println(new String(headerBytes) + ", " + key);
        dataOutputStream.write(headerBytes);
        dataOutputStream.write(key.getBytes());
//        dataOutputStream.flush();
    }

    private DataOutputStream getDataOutputStream() throws IOException {
        if(dataOutputStream == null){
            dataOutputStream = new DataOutputStream(client.getOutputStream());
        }
        return dataOutputStream;
    }

    public InputStream getInputStream() throws IOException {
        if(inputStream == null){
            inputStream = client.getInputStream();
        }
        return inputStream;
    }



    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println(args.length);
        socketClient = new SocketClient();
        socketClient.sendKey("id:" + socketClient.client.getLocalPort());
        new Thread(() -> {
            try {
                InputStream inputStream = socketClient.getInputStream();
                while (!socketClient.client.isClosed() && !socketClient.client.isInputShutdown()){
                    byte[] byteArray = new byte[5];
                    try{
                        socketClient.client.sendUrgentData(0xFF);
                    }catch (IOException e){
                        System.out.println("server occurs error! retry to connect ...");
                        return;
                    }
                    inputStream.read(byteArray);
                    String action = new String(byteArray);
                    System.out.println("received action " + action );
                    switch (action) {
                        case "audio":
                            socketClient.sendStream("/Users/ddy/Music/20190611141349.mp3");
                            break;
                        case "video":
                            socketClient.sendStream("/Users/ddy/Movies/1592807276034284.mp4");
                            break;
                        default:
                            System.out.println("action is error! :" + action);
                            return;
                    }
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        JFrame frame = new JFrame();
        frame.setSize(1920, 1080);
        frame.setVisible(true);
        frame.addMouseListener(new MouseClickListener());

        while(true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("Please input Command Key or File Path：");
            String input = sc.nextLine();
            String type, key = "", filePath = null;
            if("\\0".equals(input)){
                socketClient.close();
                break;
            }
            if (input.length() == 0) {
                type = TYPE_KEY;
                key = "Hello, this is a debug test msg";
            } else {
                filePath = input;
                File file = new File(filePath);
                if (file.exists()) {
                    type = TYPE_FILE;
                } else {
                    type = TYPE_KEY;
                    key = input;
                }
            }
            System.out.println(type + " --> " + ("".equals(key) ? filePath : key));
            switch (type) {
                case TYPE_FILE:
                    socketClient.sendFile(filePath, -1);
                    break;
                case TYPE_KEY:
                    if(key.startsWith("xy")){
                        int x=0,y=0;
                        int len = 10;
                        int count = 0;
                        for(int i=0;i<100;i++){
                            x+=len;
                            y = (int)(Math.sin(Math.PI/180 * (i - 45*count))*450) + 500;
                            if(x>1920){
                                x = 0;
                                count++;
                            }
                            System.out.print("[" + x + ", " + y + "]  ");
                            if(key.equals("xy")){
                                socketClient.sendKey("@" + x + "," + y);
                            }else{
                                socketClient.sendKey("#" + x + "," + y);
                            }
                            Thread.sleep(10);
                        }
                    }else if(key.equals("m@")) {
                        drawMouseTrack("@");
                    }else if(key.equals("m#")) {
                        drawMouseTrack("#");
                    }else{
                        socketClient.sendKey(key);
                    }
                    break;

                default:
                    socketClient.sendKey("Hello socket ~~");
            }


        }

    }

    private static void drawMouseTrack(String flag) {
        Timer timer = new Timer();
        timerCount = 0;
        final StringBuffer[] keys = {new StringBuffer()};
        try {
            socketClient.sendCursorHeader();
        } catch (IOException e) {
            e.printStackTrace();
        }
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                timerCount++;
                Point point = MouseInfo.getPointerInfo().getLocation();
                keys[0].append(flag).append(point.x).append(",").append(point.y).append(",").append(mouseStatus[0]).append("$");
                if(timerCount % 5 == 0 ){
                    try {
                        socketClient.sendCursor(keys[0].toString());
                        keys[0] = new StringBuffer();
                    } catch (IOException e) {
                        e.printStackTrace();
                        timer.cancel();
                    }
                }
                if(timerCount > 20000){
                    timer.cancel();
                    try {
                        socketClient.sendEndFlag();
                    } catch (InterruptedException | IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, 0,1);
    }


    static class MouseClickListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            int button = e.getButton();
            if(button == MouseEvent.BUTTON1){
                changeMouseStatus(1);
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            int button = e.getButton();
            if(button == MouseEvent.BUTTON1){
                changeMouseStatus(0);
            }
        }
    }

    private static void changeMouseStatus(int mouseValue){
        synchronized (mouseStatus){
            mouseStatus[0] = mouseValue;
            System.out.println("value changed: " + mouseValue);
        }
    }
}
